// Created by Laurent Mignonneau
// Advanced course example
// May 2011

// works with a 7x5 dot matrix display

// columns and rows are connected as follows
byte col[5] = {2, 3, 4, 5, 6};
byte row[7] = {7, 8, 9, 10, 11, 12, 13};

// six motifs is the original render view
byte motif[4][5][7]={ 
   {{1, 1, 1, 1, 1, 1, 1},
   {1, 1, 1, 1, 1, 1, 1},
   {1, 1, 0, 0, 0, 1, 1},
   {1, 1, 1, 1, 1, 1, 1},
   {1, 1, 1, 1, 1, 1, 1}},
   
   {{1, 1, 1, 1, 1, 1, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 1, 1, 1, 1, 1, 1}},
   
   {{1, 1, 0, 0, 0, 1, 1},
   {1, 0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0, 0, 1},
   {1, 1, 0, 0, 0, 1, 1}},
   
   {{1, 0, 0, 0, 0, 0, 1},
   {0, 0, 0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, 0},
   {1, 0, 0, 0, 0, 0, 1}}};
   


long previousMillis = 0; 
long interval = 50; // Ein Interval von 50ms entspricht 20Frames per second
int frameCounter = 0;

int index;
byte valueController = 1;
const int xpin = 3;                   // x-axis of the accelerometer
const int ypin = 2;                   // y-axis
const int zpin = 1;    
boolean stopReading = true;
int stopReadingCounter = 0;
int stopReadingDuration = 40; // value in Frames - 30 Frames ?!
boolean debug = false; // If you want to debug your code, change it to true and check the Serial Monitor
int screenIndex = 0;
boolean borderCollision = false;
boolean itemCollision = false;

int ballX_old = 3;
int ballY_old = 2;
int ballX = 3; // 3 Y axis because of the display rotation... // 7
int ballY = 2; // 2 X axis ..... // 5
int ballVertical_old = 0;
int ballHorizontal_old = 0;
int ballVertical = 0;   // 1 = right, 0 = no move, -1 = left // 5
int ballHorizontal = 0; // -1 = up, 0 = no move, 1 = down  // 7

/////////////////////////////////////////////////////
// SETUP THIS WHOLE SHIT
void setup() {                
  // initialize the digital pin as outputs.
  pinMode(2, OUTPUT);     
  pinMode(3, OUTPUT);     
  pinMode(4, OUTPUT);     
  pinMode(5, OUTPUT);     
  pinMode(6, OUTPUT);     
  pinMode(7, OUTPUT);     
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT);     
  pinMode(10, OUTPUT);     
  pinMode(11, OUTPUT);     
  pinMode(12, OUTPUT);     
  
  
  // only one col at a time (here LOW means that the column is making the row LEDs visible !)
  digitalWrite(2, HIGH);   // set col LED off
  digitalWrite(3, HIGH);   // set col LED off
  digitalWrite(4, HIGH);   // set col LED off
  digitalWrite(5, HIGH);   // set col LED off
  digitalWrite(6, HIGH);   // set col LED off

  // 7 pixels visible in one col
  digitalWrite(7, HIGH);   // set the LED on
  digitalWrite(8, HIGH);   // set the LED on
  digitalWrite(9, HIGH);   // set the LED on
  digitalWrite(10, HIGH);   // set the LED on
  digitalWrite(11, HIGH);   // set the LED on
  digitalWrite(12, HIGH);   // set the LED on
  digitalWrite(13, HIGH);   // set the LED on
  
  Serial.begin(9600);

}

void loop() {
  
  ////////////////////////////////////////////////
  // Game Logic
  unsigned long currentMillis = millis();
  
  // Check if a new Frame is reached
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis; 
    frameCounter++;
    
   // Only each 5th frame executes this code
   if(frameCounter > 5) {
	 frameCounter = 0;
         
         ballX_old = ballX;
         ballY_old = ballY;
         ballHorizontal_old = ballHorizontal;
         ballVertical_old = ballVertical;
         
         ballX = ballX + ballHorizontal;
         ballY = ballY + ballVertical;
         
                  
         //////////////////////////////
         // Border Collision check
         if(ballY<0) {
           borderCollision = true;
           ballVertical = 1;
         }
         if(ballY > 4) {
           borderCollision = true;
           ballVertical = -1;
         }
         if(ballX<0) {
           borderCollision = true;
           ballHorizontal = 1;
         }
         if(ballX > 6) {
           borderCollision = true;
           ballHorizontal = -1;
         }
         //Border Collision Movement
         if(borderCollision) {
           ballX = ballX_old + ballHorizontal;
           ballY = ballY_old + ballVertical;
           borderCollision = false;
         }
        
//         Serial.println("\nBallPosition");
//         Serial.print(ballX);
//         Serial.print(" / ");
//         Serial.print(ballY);
         renderBall();
         
         // checking if the game is finished 
         byte itemCounter = 0;
         for(byte tY = 0; tY < 5; tY++) {
           for(byte tX = 0; tX < 7;tX++) {
             if(motif[screenIndex][tY][tX] == 1) itemCounter++;
           }  
         }
         
         if(itemCounter == 1)
           gameRestart();
    }
    
  } // End Timer intervall 
  
  ////////////////////////////////////////////////
  // Map the game data to the screen
  // Render the data directly for the hardware
  renderHardware();
  if(debug) debugHardwareScreen();  
}
/////////////////////////////////////////////////////////////////////////
////////////////// Functions ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
void gamerInteraction()
{
  unsigned long currentMillis = millis(); 
  // Check if a new Frame is reached
  if(currentMillis - previousMillis > interval) {
    //int ballVertical = 0;   // 1 = right, 0 = no move, -1 = left // 5
    //int ballHorizontal = 1; // -1 = up, 0 = no move, 1 = down  // 7
    
    
    if(!stopReading) {
      int xMovement = analogRead(xpin);
      int yMovement = analogRead(ypin);
      
      /*Serial.print(xMovement);
      Serial.print("\t");
      Serial.print(yMovement);
      Serial.println();*/
      if(xMovement >= 380) {
        // Movement left - value 380 or 430;
        if(ballY > 0 && ballVertical > -1) ballVertical--;
        stopReading = true;
      } else if (xMovement <= 325) {
        // Movement right - value 325 or 270
        if(ballY < 4 && ballVertical < 1) ballVertical ++;
        stopReading = true;
      } else {
        // no Real Movement
        //stopReading = false;
      }
      
      if(yMovement >= 400) {
        // Movement up / front - value 400 or 430
        if(ballX > 0 && ballHorizontal > -1) ballHorizontal--;
        stopReading = true;
      } else if(yMovement <= 330) {
        // Movement down / behind - value 330 or 280
        if(ballX < 6 && ballHorizontal < 1) ballHorizontal++;
        stopReading = true;
      } else {
        // no real Movement
        //stopReading = false;
      }
      
   } else {
     stopReadingCounter++;
     if(stopReadingCounter > stopReadingDuration) {
       stopReading = false;
       stopReadingCounter = 0;  
   }
   } // End if stop reading 
    
  } // Enf if Time Interval

}
/////////////////////////////////////////////////////////////////
void gameRestart() 
{
   if(screenIndex < 3) 
     screenIndex++;
   else
     screenIndex = 0;   
   ballX_old = 3;
   ballY_old = 2;
   ballX = 3; // 3 Y axis because of the display rotation... // 7
   ballY = 2; // 2 X axis ..... // 5
   ballVertical_old = 0;
   ballHorizontal_old = 0;
   ballVertical = 0;   // 1 = right, 0 = no move, -1 = left // 5
   ballHorizontal = 0; // -1 = up, 0 = no move, 1 = down  // 7
}


//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void renderBall() 
{
  motif[screenIndex][ballY][ballX] = 1;
  motif[screenIndex][ballY_old][ballX_old] = 0;
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// display the Game Graphic on the Hardware Screen
void renderHardware()
{
  int cl;
  // each column is scanned one at a time
  for(cl=0; cl < 5; cl++)
  { 
     //turn ON the selected column first
     digitalWrite(col[cl], LOW);
     // then find out if each pixel is ON or OFF in the row
     for(index=0;index<7;index++)
     {
       if(motif[screenIndex][cl][index] < 1) digitalWrite(row[index], LOW);
       else digitalWrite(row[index], HIGH);
     }
     // slows down the loop a bit to get more light output.
     // if you need to read sensors, you can do it here instead this delay
     gamerInteraction();
     delay(1);
     // now turn OFF the current column
     digitalWrite(col[cl], HIGH);
     // well, that's it
     
  } 
}


///////////////////////////////////////////////////////////
// This functions makes your life easier for finding errors. 
// Output is generated for the Serial Monitor
void debugHardwareScreen()
{
  Serial.println("--- Hardware Screen ---");
  for(int y = 0; y < 5; y++) {
    Serial.println("");
    for(int x = 0; x < 7; x++) {
      if(motif[y][x] > 0)      
        Serial.print('1');
      else
        Serial.print('0');
    }
  }
  Serial.println("");
  Serial.println("-------------");
}

